﻿using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MsForgeReboot.Services.Tests
{
    using System.Linq;

    using Moq;

    using MsForgeReboot.Framework.Entities;
    using MsForgeReboot.Framework.Interfaces;

    using PagedList;

    [TestClass]
    public class EventServiceTests
    {
        private Mock<MsForgeContext> contextMock;
        IEventService controller;

        [TestInitialize]
        public void TestInitialize() {
            this.contextMock = new Mock<MsForgeContext>();

            this.contextMock.SetupGet(data => data.Events).Returns(TestDataGenerator.GetFakeEventInstances(15, 12));
            this.contextMock.SetupGet(data => data.UserGroups).Returns(TestDataGenerator.GetFakeUserGroupInstances(15));
            this.contextMock.SetupGet(data => data.Users).Returns(TestDataGenerator.GetFakeUserInstances(15));

            foreach (var userGroup in this.contextMock.Object.UserGroups)
            {
                userGroup.Author = this.contextMock.Object.Users.Single(u => u.Id == userGroup.Id);
            }

            this.controller = new EventService(this.contextMock.Object);
        
        }

        [TestCleanup]
        public void TestCleanup()
        {
            this.contextMock = null;
        }

        [TestMethod]
        public void UpcomingEventsShouldReturnPagedList() {
           
            var actual = this.controller.UpcomingEvents(1, 10);

            Assert.IsInstanceOfType(actual, typeof(IPagedList<Event>));
            Assert.AreEqual(10, actual.Count);
            Assert.AreEqual(1, actual.PageNumber);
            Assert.AreEqual(2, actual.PageCount);
        }


        [TestMethod]
        public void GetAllShouldReturnPagedList()
        {
            var actual = this.controller.GetAll(1, 5);

            Assert.IsInstanceOfType(actual, typeof(IPagedList<Event>));
            Assert.AreEqual(5, actual.Count);
            Assert.AreEqual(1, actual.PageNumber);
            Assert.AreEqual(3, actual.PageCount);
        }

        [TestMethod]
        public void GetByUrlPointerReturnsEvent()
        {
            var actual = this.controller.GetByUrlPointer("event-title-6");

            Assert.IsInstanceOfType(actual, typeof(Event));
        }

        [TestMethod]
        public void GetByUrlPointerReturnsCorrectEvent()
        {
            const string Expected = "event-title-6";

            var actual = this.controller.GetByUrlPointer(Expected);

            Assert.AreEqual(actual.UrlPointer, Expected);
        }

        [TestMethod]
        public void SaveShouldInsertNewEventIfIdIsZero()
        {
            this.contextMock.Setup(context => context.SaveChanges());

            var newItem = new Event() { Id = 0, Title = "New Item", Author = new User() { Id = 7 } };

            this.controller.Save(newItem);

            Assert.AreEqual(16, this.contextMock.Object.Events.Count());
        }

        [TestMethod]
        public void AuthorIsCorrectlyAssignedToEventOnSave()
        {

            this.contextMock.Setup(context => context.SaveChanges());

            var newItem = new Event() { Id = 0, Title = "New Item", Author = new User() { Id = 7 } };

            this.controller.Save(newItem);

            Assert.AreEqual(newItem.Author.Id, 7);
            Assert.AreEqual(newItem.Author.PublicName, "User 7");
            Assert.AreEqual(newItem.Author.Username, "user-name-7@domain7.com");
        }

        [TestMethod]
        public void SaveShouldUpdateExistingEventIfIdIsNotEqualToZero()
        {
            this.contextMock.Setup(context => context.SaveChanges());
            var expected = new Event() { Id = 5, Title = "Updated Title", Author = new User() { Id = 7 } };

            this.controller.Save(expected);

            var actual = this.contextMock.Object.Events.Single(item => item.Id == 5);

            Assert.AreEqual(15, this.contextMock.Object.UserGroups.Count());
            Assert.AreEqual(expected.Title, actual.Title);
        }
    }
}
